#include "lib.h"
#include "slotconn.h"
#include "sltsql.h"
#include "progsql.h"
#include "slotopts.h"
#include "odbc.h"
#include "opts.h"
#include "slotspin.h"
#include "missinggamenums.h"

SlotsSQL::SlotsSQL(const String& DBDSN, const String& DBLogin, const String& DBPassword)
	: ProgressiveTrackSQL(DBDSN, DBLogin, DBPassword)
{
#ifdef USE_MISSINGGAMENUMS
	//missing game nums deleted in TrackSQL::~TrackSQL
	missinggamenums = new MissingGameNums(this, "pub_getTableIdentitySlots");
#endif
}

int32
SlotsSQL::getSubGameData(SubGame *subGame)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        query = conn->query();
        if (query)
        {
            query->define("exec pub_SlotsGetSubGameData ");
            query->addParam(subGame->getMachid(), ODBCQuery::BINARY);
            query->addParam(subGame->getPid());
            query->addParam(subGame->getCreditValue());
            query->addParam((bool8)(subGame->isForMoney() != 0));
    
            if (query->exec())
            {
                uint8 id;
                int32 data;
                bool8 serverOnly;
                ok = true;
				while ( ok && query->getRow() )
				{
                    ok = query->getData(1, &id);
                    if ( ok )
                    {
                        ok = query->getData(2, &data);
                    }
                    else
                    {
                        /**
                         * Problem with Id.
                         */
                        ASSERT(0);
                    }

                    if ( ok )
                    {
                        ok = query->getData(3, &serverOnly);
                    }
                    else
                    {
                        /**
                         * Problem with Data.
                         */
                        ASSERT(0);
                    }


                    if ( ok )
                    {
						subGame->setServerOnly(id, serverOnly);
						subGame->update(id, data);
                    }
                    else
                    {
                        /**
                         * Problem with serverOnly.
                         */
                        rc = ExecFailed;
                    }

                }
            }
            delete query;
        }
        else
        {
            rc = NoConnection;
        }
    	delete conn;
    }
    else
    {
		rc = NoConnection;
    }

    return rc;

}



int32
SlotsSQL::setSubGameData(SubGame *subGame)
{
	ODBCConnection* conn;
	ODBCQuery* query;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        rc = NoError;
        for ( int i = 0; rc == NoError && i < subGame->getDataCount(); i++ )
        {
            query = conn->query();
            if (query)
            {
                query->define("exec pub_SlotsSetSubGameData ");
                query->addParam(subGame->getMachid(), ODBCQuery::BINARY);
                query->addParam(subGame->getPid());
                query->addParam(subGame->getCreditValue());
                query->addParam((bool8)(subGame->isForMoney() != 0));
                query->addParam(subGame->getIdAt(i));
                query->addParam(subGame->getDataAt(i));
                query->addParam(subGame->isServerOnlyAt(i));


                if (query->exec())
                {
                    rc = NoError;
                }
                else
                {
                    /**
                     * Unable to execute query.
                     */
                    ASSERT(0);
                    rc = ExecFailed;
                }
                delete query;
            }
            else
            {
                rc = NoConnection;
            }
        }
    	delete conn;
    }
    else
    {
		rc = NoConnection;
    }

    return rc;

}

int32
SlotsSQL::archiveSubGameData(int32 gamenum, SubGame *subGame)

{
	ODBCConnection* conn;
	ODBCQuery* query;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        rc = NoError;
        for ( int i = 0; rc == NoError && i < subGame->getDataCount() && gamenum > 0; i++ )
        {
            query = conn->query();
            if (query)
            {
                query->define("exec pub_SlotsArchiveSubGameData ");
                query->addParam(gamenum);
                query->addParam(subGame->getIdAt(i));
                query->addParam(subGame->getDataAt(i));

                if (query->exec())
                {
                    rc = NoError;
                }
                else
                {
                    /**
                     * Unable to execute query.
                     */
                    rc = ExecFailed;
                }
                delete query;
            }
            else
            {
                rc = NoConnection;
            }
        }
    	delete conn;
    }
    else
    {
		rc = NoConnection;
    }

    return rc;

}

        
bool8 
SlotsSQL::createBonusGame( SlotGuts *guts, int32 gamenum, uint8 linenumber, uint8 bonusgamenum, uint8 bonusgametype, uint8 playerchoice, int32 winresult)
{
	ODBCConnection* conn;
	ODBCQuery* query;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        query = conn->query();
        if (query)
        {
            rc = NoError;
            query->define("exec pub_SlotsCreateBonusGame ");
            query->addParam(gamenum);
            query->addParam(guts->getInfo()->pid);
			query->addParam(guts->getMachId(), ODBCQuery::BINARY);
            query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
            query->addParam((bool8)(guts->isForMoney() != 0));
			query->addParam(linenumber);
            query->addParam(bonusgamenum);
            query->addParam(bonusgametype);
            query->addParam(playerchoice);
            query->addParam(winresult,ODBCQuery::MONEY);
                
            if (query->exec())
            {
                rc = NoError;
            }
            else
            {
                /**
                 * Unable to execute query.
                 */
                rc = ExecFailed;
            }
            delete query;
        }
        else
        {
            /**
             * Unable to create query
             */
            rc = NoConnection;
        }
    	delete conn;
    }
    else
    {
        /**
         * Unable to connect
         */
		rc = NoConnection;
    }

    return rc;
}

bool8
SlotsSQL::getGutsName(int32 gutsId, char* name)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetGutName ");
		query->addParam(gutsId);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok = query->getData(1, name,64);

                if ( !ok )
                {
                    /**
                     * Unable to get Name.
                     */
                    ASSERT(0);
                    break;
                }

			}
		}
		delete query;
	}
	delete conn;

	return ok;
}




int32
SlotsSQL::getPlayerLimits(const PID& pid, int32 gameId, uint8 machId,
	int32* compFactor)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_lim_getPlayerLimits ");
		query->addParam(pid);
		query->addParam(gameId);
		query->addParam(machId, ODBCQuery::BINARY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok = query->getData(4, compFactor);

                if ( !ok )
                {
                    /**
                     * Unable to get compFactor.
                     */
                    ASSERT(0);
                    break;
                }

			}
		}
		delete query;
	}
	delete conn;

	return ok ? isGameEnabled(gameId,machId) : ExecFailed;
}


bool8
SlotsSQL::createWheels(SlotSpin *spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (conn)
    {
        for ( uint8 reelidx = 0; reelidx < spin->getStopCount(); reelidx++ )
        {
    	    query = conn->query();
    	    if (query)
    	    {
                query->define("exec pub_SlotsCreateWheel ");
                query->addParam(spin->getGameNum(), ODBCQuery::NOTMONEY);
                query->addParam(reelidx);
                query->addParam(spin->getStops()[reelidx]);
        
                ok = query->exec();

                if ( !ok )
                {
                    /**
                     * Unable to execute query.
                     */
                    ASSERT(0);
                }
                delete query;
            }
            else
            {
                /**
                 * Bad query.
                 */
                ASSERT(0);
            }
    
        }
        delete conn;
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}

int32 
SlotsSQL::createWin(int32 casinoId, 
                    const PID& pid,
                    bool8 forMoney,
                    int32 compFactor,
                    int32 gamenum,
                    uint8 lineid,
                    uint8 payouttypeid,
                    int32 payoutamount,
                    int32 *balance,
                    bool8 jackpot)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_SlotsCreateWin ");
            query->addParam(casinoId);
            query->addParam(pid);
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam((bool8)(forMoney != 0));
            query->addParam(compFactor);
            query->addParam(lineid);
            query->addParam(payouttypeid);
            query->addParam(payoutamount, ODBCQuery::MONEY);
            query->addParam(jackpot);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of createWin.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
        delete conn;
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;

}

int32 
SlotsSQL::createScatterResults( int32 gamenum,      
                                int32 scatterpos, 
                     	        uint8 payouttypeid, 
                                int32 payoutamount,
                     	        bool8 jackpot)

{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_SlotsCreateScatterResults ");
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(scatterpos);
            query->addParam(payouttypeid);
            query->addParam(payoutamount, ODBCQuery::MONEY);
            query->addParam(jackpot);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of createScatterResults.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
        delete conn;
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}
		
int32 
SlotsSQL::saveSpins(int32 casinoId, SlotGuts *guts)
{
    SlotSpin *spin;
	bool8 ok = true;

    for ( uint8 spinid = 0; ok && spinid < guts->getSlotSpinCount(); spinid++ )
    {
        spin = guts->getSlotSpin(spinid);

        if ( spin->isSpinComplete() && !spin->isSpinSaved() )
        {
            /**
             * Save the wins.
             */
            for ( uint8 lineidx = 0; ok && lineidx < spin->getSpinLineCount(); lineidx++ )
            {
                const SpinLine *spinLine = spin->getSpinLineAt(lineidx);

				if(guts->shouldSaveGameData())
				{
					ok = createWin(casinoId, 
								   guts->getInfo()->pid, 
								   guts->getInfo()->forMoney, 
								   guts->getInfo()->compFactor, 
								   spin->getGameNum(), 
								   spinLine->lineid, 
								   spinLine->payouttypeid,
								   spinLine->payoutamount,
								   &guts->getInfo()->balance,
								   spinLine->jackpot);
				}
				else
				{
					//if we are not saving fun play game data, then we manually
					//add any payout wins to the fun account
					if(spinLine->payoutamount > 0)
					{
						int32 comp;
						adjustBalance(casinoId,guts->getInfo()->pid,false,spinLine->payoutamount,&guts->getInfo()->balance,&comp);
					}
				}

                if (!ok)
                {
                    break;
                }

            }
    
            if ( ok )
            {
				if(guts->shouldSaveGameData())
				{
					ok = createWheels(spin);
				}
            }
            else
            {
                /**
                 * unable to create win.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                for ( uint8 scatterIndex = 0; ok && scatterIndex < spin->getNumScatters(); scatterIndex++ )
                {
                    SlotScatter* pScatter = spin->getScatter(scatterIndex);

					if(guts->shouldSaveGameData())
					{
						ok = createScatterResults( spin->getGameNum(),
												   pScatter->scatterposition,
												   pScatter->payouttypeid,
												   pScatter->payoutamount,
												   pScatter->jackpot);
					}
					else
					{
						//if we are not saving fun play game data, then we manually
						//add any scatter wins to the fun account
						if(pScatter->payoutamount > 0)
						{
							int32 comp;
							adjustBalance(casinoId,guts->getInfo()->pid,false,pScatter->payoutamount,&guts->getInfo()->balance,&comp);
						}
					}

                    if (!ok)
                    {
                        break;
                    }
                }
            }
            else
            {
                // Unable to create wheels
            }

            if ( ok )
            {
                spin->setSpinSaved(true);
            }

        }

        if ( !ok )
        {
            /**
             * unable to create scatters
             */
            ASSERT(0);
        }
    }

	return ok ? NoError : ExecFailed;

}



int32 
SlotsSQL::saveGame(int32 casinoId, SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
    int32 gameNum;

	conn = getConn();
	if ( conn )
    {
        for ( uint8 spinid = 0; ok && spinid < guts->getSlotSpinCount(); spinid++ )
        {
    	    query = conn->query();
    	    if (query)
    	    {
                SlotSpin *spin = guts->getSlotSpin(spinid);
                int32 progBet, adjustedBet;

                /** 
                 * Only save a spin if it has yet to be saved.
                 */
                if ( spin->getGameNum() == 0 )
                {
                    if ( guts->isProgressive() )
                    {
                        progBet = spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->creditValue;
                        adjustedBet = 0;
                    }
                    else
                    {
                        adjustedBet = spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->creditValue;
                        progBet = 0;
                    }
    
					if(guts->shouldSaveGameData())
					{
						query->define("exec pub_SlotsCreateGame ");
						query->addParam(casinoId);
						query->addParam(guts->getInfo()->pid);
						query->addParam(guts->getMachId(), ODBCQuery::BINARY);
						query->addParam((int32)guts->getInfo()->creditValue);
						query->addParam((bool8)(guts->isForMoney() != 0));
						query->addParam(guts->getInfo()->sessionId, ODBCQuery::NOQUOTES);
						query->addParam((int32) (guts->getInfo()->forMoney ? guts->getInfo()->compFactor : 0), ODBCQuery::NOTMONEY);
						query->addParam(spin->getBet());
						query->addParam((int32)(spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->creditValue), ODBCQuery::MONEY);
						query->addParam(spin->getSpinLineCount());
						query->addParam(adjustedBet, ODBCQuery::MONEY);
						query->addParam(progBet, ODBCQuery::MONEY);
						query->addParam(spin->getMultibankBet(), ODBCQuery::MILLIMONEY);
						query->addParam(guts->getGutsId());
						query->addParam(spin->getBonusGameType());
						query->addParam(guts->getReferenceGameNum());
						query->addParam(guts->isMalfunction());
						query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
	        
						if (query->exec())
						{
							query->getRow();
	        
							ok = query->getData(1, &guts->getInfo()->balance, ODBCQuery::MONEY);
	                         
							if ( ok )
							{
								// ok = query->getData(3, &gameNum);
								ok = query->getData(3, &gameNum); 
							}
							else
							{
								/**
								 * unable to get balance
								 */
								ASSERT(0);
							}
	        
							if ( ok )
							{
								spin->setGameNum(gameNum);
#ifdef USE_MISSINGGAMENUMS
								if (missinggamenums)
									missinggamenums->setGameNum(gameNum);
#endif
							}
							else
							{
								/**
								 * unable to get gamenum
								 */
								ASSERT(0);
							}
						}
						else
						{
							/**
							 * Bad exec of create game.
							 */
							ASSERT(0);
						}
					}
					else
					{
						//if we are not saving fun play game data, then we
						//manually remove the bet amount from the account when it is made
						int32 comp;
						adjustBalance(casinoId,guts->getInfo()->pid,false,-(adjustedBet+progBet),&guts->getInfo()->balance,&comp);
					}
                }
        		delete query;
            }
            else
            {
                /**
                 * Bad query.
                 */
                ASSERT(0);
            }
    	}
	    delete conn;
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }


	return ok ? NoError : ExecFailed;

}






/**
 * @brief get the reels from the database.
 * 
 */
bool8
SlotsSQL::getGutsReels(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_SlotsGetGutsReels ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
            uint8 reelid;
            uint8 position;
            uint8 iconid;
            int64 weight;
            char iconName[64];
    
            guts->clearWheelhouse();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &reelid);
                if ( ok )
                {
                    ok = query->getData(column++, &position);
                }
                else
                {
                    /**
                     * Unable to get reelid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &iconid);
                }
                else
                {
                    /**
                     * Unable to get position.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &weight);
                }
                else
                {
                    /**
                     * Unable to get iconid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, iconName, sizeof(iconName));
                }
                else
                {
                    /**
                     * Unable to get weight.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addIcon(reelid, iconid, position, weight, iconName);
                }
                else
                {
                    /**
                     * Unable to get icon name.
                     */
                    ASSERT(0);
                }

            }
        }
        delete query;
    }
	delete conn;

    return ok;
}

/**
 * @brief get the paylines from the database.
 * 
 */
bool8
SlotsSQL::getGutsPaylines(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_SlotsGetGutsPaylines ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
            uint8 paylineid;
            uint8 reelid;
            uint8 wheelposition;
    
            guts->clearPaylines();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &paylineid);

                if ( ok )
                {
                    ok = query->getData(column++, &reelid);
                }
                else
                {
                    /**
                     * Invalid paylineid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &wheelposition);
                }
                else
                {
                    /**
                     * Invalid reelid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addPayline(paylineid, reelid, wheelposition);
                }
                else
                {
                    /**
                     * Invalid wheel position.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}




/**
 * @brief get the payouts from the database.
 * 
 */
bool8
SlotsSQL::getGutsPayouts(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_SlotsGetGutsPayouts ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
           uint8    payoutTypeId;
           uint8    betAmount;
           char     payoutName[64];
           int32    payoutAmount;
    
            guts->clearPayTable();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &payoutTypeId);
                if ( ok )
                {
                    ok = query->getData(column++, &betAmount);
                }
                else
                {
                    /**
                     * Unable to get payout type id.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, payoutName, sizeof(payoutName));
                }
                else
                {
                    /**
                     * Unable to get bet amount.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &payoutAmount);
                }
                else
                {
                    /**
                     * Unable to get payout name.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addPayout(payoutTypeId, betAmount, payoutName, payoutAmount);
                }
                else
                {
                    /**
                     * Unable to get payout amount.
                     */
                    ASSERT(0);
                }
            }
        }
        delete query;
    }
    else
    {
        /**
         * Invalid query object.
         */
        ASSERT(0);
    }
    delete conn;

    return ok;
}



/**
 * @brief get the guts from the database.
 * 
 */
int32 
SlotsSQL::getGuts(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        /**
         * Get the gutsid.
         */
		query->define("exec pub_SlotsGetOptions ");
        query->addParam(guts->getMachId());
        query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);

		if (query->exec())
		{
            int32 gutsId;
            int32 jackpotId;
            bool8 progressive;
            bool8 bFastPlayEnabled;

            /**
             * Only 1 row, no need for a loop.
             */
			ok = false;
			if ( query->getRow() )
			{
				ok = true;
			}

            int column = 1;
			if ( ok )
			{
				ok = query->getData(column++, &gutsId);
			}
			else
			{
                /**
                 * Unable to get row.
                 */
                ASSERT(0);
			}

            if ( ok )
            {
                ok = query->getData(column++, &jackpotId);
            }
            else
            {
                /**
                 * Unable to get gutsId.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                ok = query->getData(column++, &progressive);
            }
            else
            {
                /**
                 * Unable to get jackpotid.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
				column++;
            }
            else
            {
                /**
                 * Unable to get  progressive.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                ok = query->getData(column++, &bFastPlayEnabled);
            }
            else
            {
                /**
                 * Unable to get fast play enabled.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                guts->setGutsId(gutsId);
                guts->setJackpotId(jackpotId);
                guts->setProgressive(progressive);
                guts->setFastPlayEnabled( bFastPlayEnabled );
            }
            else
            {
                /**
                 * Unable to get Fast Play Enabled flag.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                ok = this->getGutsPayouts(guts);
            }

            if ( ok )
            {
                ok = this->getGutsReels(guts);
            }

            if ( ok )
            {
                ok = this->getGutsPaylines(guts);
            }

            if ( ok )
            {
                ok = this->getGutsDenominations(guts);
            }
        }

		delete query;
	}
	delete conn;

	return ok ? NoError : ExecFailed;
}


int32
SlotsSQL::getSavedGame(SlotGuts* guts, int32 *gutsid, int32 *gamenum,uint8* bonusgamenum, bool8 *malfunctioned, bool8 *completed) 
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetSavedGame ");		
        query->addParam(guts->getMachId(), ODBCQuery::BINARY);
        query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
		query->addParam(guts->getInfo()->pid);
		query->addParam((bool8)(guts->isForMoney() != 0));
		if (query->exec())
        {
  
                /**
                 * Only 1 row, no need for a loop.
                 */

                int column = 1;

				ok = (query->getRow() && query->getData(column++,gamenum));  

				//gamenum
				if ( ok )
                {
                    ok = query->getData(column++, gutsid);
                }
                else
                {
                    /**
                     * Unable to get gamenum, but that's okay
                     */
                    *gamenum = -1;
                }
				if ( ok )
                {
                    ok = query->getData(column++, bonusgamenum);
                }
                else
                {
                    /**
                     * Unable to get gutsid, but that's okay
                     */
                    *gamenum = -1;
                }
				if( ok)
				{
					ok = query->getData(column++,malfunctioned);
				}
                else
                {
                    /**
                     * Unable to get bonusgamenum, but that's okay
                     */
                    *gamenum = -1;
                }

				if( ok)
				{
					ok = query->getData(column++,completed);
				}
                else
                {
                    /**
                     * Unable to get malfunctioned, but that's okay
                     */
                    *gamenum = -1;
                }

				if(!ok)
				{
                    /**
                     * Unable to get completed,, but that's okay
                     */
                    *gamenum = -1;
				}

            }
            else
            {
                /**
                 * Unable to execute query.
                 */
                *gamenum = -1;
            }
	} // if query
	delete query;
	delete conn;
	if(ok)
	{
		return SlotsSQL::NoError;
	}
	else
	{
		return SlotsSQL::ExecFailed;
	}
}


bool8
SlotsSQL::loadGameDataIntoSpin(int32 gamenum, SlotGuts* guts, SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 bet=0;
	uint8 linesbet=0;
	int32 totalPayout=0;
    uint8 coinsbet=0;

	conn = getConn();
	if (!conn)
		return NoConnection;

	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetGame ");
        query->addParam(gamenum);
		if (query->exec())
		{
            /**
             * Only 1 row, no need for a loop.
             */
			query->getRow();  

			int column = 1;
			ok = query->getData(column++, &bet,ODBCQuery::MONEY);
			if(ok)
			{
				ok = query->getData(column++, &linesbet);
			}
			else
			{
				ASSERT(0); //Problem with bet
			}
			if(ok)
			{
				ok = query->getData(column++, &totalPayout,ODBCQuery::MONEY);
			}
			else
			{
				ASSERT(0); //Problem with the lines bet
			}
			if(ok)
			{
				ok = query->getData(column++, &coinsbet);
			}
			else
			{
				ASSERT(0); //Problem with total payout
			}
			if(!ok)
			{
				ASSERT(0); //Problem with coins bet
			}
		}//query exec
	} //conn->query
	delete query;	
	delete conn;
	if(ok)
	{
        guts->getInfo()->creditValue = 0;

        if ( linesbet > 0 && coinsbet > 0 )
        {
            guts->getInfo()->creditValue = bet/(linesbet*coinsbet);
        }
        else
        {
            // We should not reach this code - there should not
            // be a saved game to restore that has no lines bet or coins bet.
            // BUT -- in case that assumption is wrong...
            ASSERT(false);
        }
        
        spin->setGameNum(gamenum);
        if ( guts->getInfo()->creditValue > 0 )
        {
    		spin->setBet((bet/linesbet)/guts->getInfo()->creditValue);
        }
        else
        {
            // I added coinsBet to the above query to 
            // calculate the credit value on a restore.
            // however, credit value should not be 
            // zero after a restore.  In case it is,
            // assign coinsBet from the record.  But
            // let's ASSERT so we know the assumption was incorrect.
		    spin->setBet(coinsbet);
            ASSERT(false);
        }
		spin->setBonusGameType((guts->getSubGame())->getDataAt(0));

        ok = loadWinsDataIntoSpin(spin);
        ok = loadScatterResultsDataIntoSpin(spin);
		ok = loadStopsIntoSpin(spin,guts->getReelCount());
	}

	if(ok)
	{
		return SlotsSQL::NoError;
	}
	else
	{
		return SlotsSQL::ExecFailed;
	}
}

bool8
SlotsSQL::loadWinsDataIntoSpin(SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();
	
	uint8 lineNumber,payoutType;
	int32 payout;
	bool8 jackpot;
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetWins ");
        query->addParam(spin->getGameNum());
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				int column = 1;
				ok = query->getData(column++, &lineNumber);
				if(ok)
				{
					ok = query->getData(column++, &payoutType);
				}
				else
				{
					ASSERT(0); //Problem with lineNumber
				}
				if(ok)
				{
					ok = query->getData(column++, &payout,ODBCQuery::MONEY);
				}
				else
				{
					ASSERT(0); //Problem with the payout type
				}
				if(ok)
				{
					ok = query->getData(column++,&jackpot);
				}
				else
				{
					ASSERT(0); //Problem with the payout amount
				}
				if(ok)
				{
					spin->addLine(lineNumber);
					spin->setPayoutAmount(lineNumber,payout,jackpot,payoutType);
					spin->setSpinSaved(true);
				}
				else
				{
					ASSERT(0); //Problem with the jackpot flag
				}

			}//while getRow()
		}//if (query->exec())
	} //if(query)
	delete query;
	delete conn;
	return ok;
}

bool8
SlotsSQL::loadScatterResultsDataIntoSpin(SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();
	
    int32 scatterpos=0; 
    uint8 payouttypeid=0; 
    int32 payoutamount=0;
    bool8 jackpot=0;
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetScatterResults ");
        query->addParam(spin->getGameNum());
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				int column = 1;

				ok = query->getData(column++, &scatterpos);

                if (ok)
				{
					ok = query->getData(column++, &payouttypeid);
				}
				
                if (ok)
				{
					ok = query->getData(column++, &payoutamount,ODBCQuery::MONEY);
				}
				
                if (ok)
				{
					ok = query->getData(column++,&jackpot);
				}
				
                if (ok)
				{
                    spin->addScatter(scatterpos, payoutamount, jackpot, payouttypeid );
				}
                else
                {   
                    // Use column to determine which getData failed.
                    ASSERT(false);
                }

			}//while getRow()
		}//if (query->exec())
	} //if(query)
	delete query;
	delete conn;
	return ok;
}

bool8
SlotsSQL::loadStopsIntoSpin(SlotSpin* spin, uint8 numStops)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();

	uint8* stops = new uint8[numStops];
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetWheels ");
		query->addParam(spin->getGameNum());
		int8 stopNum = -1;
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				stopNum++;
				if(stopNum>=numStops)
				{
					ASSERT(0); //Got more stops than we expected
				}
				ok = query->getData(2, &stops[stopNum]);
				if(!ok)
				{
					ASSERT(0); //Problem with lineNumber
				}

			}//while getRow

		}//if (query->exec())
		
		spin->setStops(stopNum+1,stops);
	} //if(query)

	delete query;
	delete conn;
	return ok;
}


bool8
SlotsSQL::loadBonusGamesIntoSpin(SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();

	uint8 bonusGameNum;
	uint8 playerChoice;
	int32 bonusPay;
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_SlotsGetWheels ");
		query->addParam(spin->getGameNum());
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				ok = query->getData(2, &bonusGameNum);
				if(ok)
				{
					query->getData(4, &playerChoice);
				}
				else
				{
					ASSERT(0); //Problem with bonusgamenum
				}
				if(ok)
				{
					query->getData(5, &bonusPay, ODBCQuery::MONEY);
				}
				else
				{
					ASSERT(0); //Problem with playerChoice
				}
				if(ok)
				{
					spin->addBonusGame(bonusGameNum,playerChoice,bonusPay);
				}
				else
				{
					ASSERT(0); //Problem with bonusPay
				}

			}//while getRow

		}//if (query->exec())
		
	} //if(query)

	delete query;
	delete conn;
	return ok;
}



        
bool8
SlotsSQL::completeGame(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	int32 throwawayComp;

	conn = getConn();
	if (!conn)
		return NoConnection;

    for ( uint8 spinid = 0; ok && spinid < guts->getSlotSpinCount(); spinid++ )
    {
	    query = conn->query();
	    if (query)
	    {
            SlotSpin *spin = guts->getSlotSpin(spinid);
            int32 progBet;


            if ( guts->isProgressive() )
            {
                progBet = spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->creditValue;
            }
            else
            {
                progBet = 0;
            }


            query->define("exec pub_SlotsCompleteGame ");

            query->addParam(ServerOpts::casinoId);
            query->addParam(guts->getInfo()->pid);
            query->addParam(guts->getMachId(), ODBCQuery::BINARY);
            query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
            query->addParam((bool8)(guts->isForMoney() != 0));
            query->addParam(guts->getInfo()->sessionId, ODBCQuery::NOQUOTES);
            query->addParam((int32)(spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->creditValue), ODBCQuery::MONEY);
            query->addParam(progBet, ODBCQuery::MONEY);
            query->addParam((int32)spin->getMultibankPayout(), ODBCQuery::MILLIMONEY);
			query->addParam(spin->getGameNum());
			query->addParam(guts->getGutsId());
    
            if (query->exec())
            {
                ok = true;

                /**
                 * Only 1 row, no need for a loop.
                 */
                query->getRow();  

                int column = 1;

                ok = query->getData(column++, &guts->getInfo()->balance, ODBCQuery::MONEY);

                if ( ok )
                {
                    ok = query->getData(column++, &throwawayComp);
                }
                else
                {
                    /**
                     * Unable to get balance
                     */
                    ASSERT(0);
                }

                if ( !ok )
                {
                    /**
                     * Unable to get comps
                     */
                    ASSERT(0);
                }
            }
            else
            {
                /**
                 * Unable to execute query.
                 */
                ASSERT(0);
            }
            delete query;
        }
    }
	delete conn;

    return ok;
}


		
int32
SlotsSQL::createSavedGame(const PID& pid, uint8 machid, int16 creditValue, bool8 forMoney, int32 gamenum, int32 gutsid, uint8 bonusGameNum)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if ( conn )
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_SlotsCreateSavedGame ");
            query->addParam(pid);
            query->addParam(machid, ODBCQuery::BINARY);
            query->addParam((int32) creditValue, ODBCQuery::NOTMONEY);
            query->addParam((bool8) forMoney);
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(gutsid);
            query->addParam(bonusGameNum);

            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Unable to execute query.
                 */
                ASSERT(0);
            }
            delete query;
        }
	    delete conn;
    }
    else
    {
        /**
         * Invalid connection.
         */
        ASSERT(0);
    }


	return ok ? NoError : ExecFailed;
}



/**
 * @brief get the denominations from the database.
 * 
 */
bool8
SlotsSQL::getGutsDenominations(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

    localCurrency lc;
    ok = GetLocale(&lc);

    if (!ok)
    {
        return ok;
    }

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_GetGameDenominations ");
        query->addParam((int32)GAMEID);
        query->addParam(guts->getMachId());
        query->addParam(lc.int_curr_symbol);
    
        if (query->exec())
        {
            uint16  machineSubId;
            uint16  creditValue;
            bool8   isDefault;
    
            guts->clearDenominations();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, (int16*)&machineSubId);

                if ( ok )
                {
                    ok = query->getData(column++, (int16*)&creditValue);
                }
                else
                {
                    /**
                     * Invalid subMachineId.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &isDefault);
                }
                else
                {
                    /**
                     * Invalid creditValue.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
					if (guts->getInfo()->machineSubID == machineSubId)
						guts->getInfo()->creditValue = creditValue;

                    guts->addDenomination(machineSubId, creditValue, isDefault);
                }
                else
                {
                    /**
                     * Invalid isDefault.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}


/**
 * @brief get the denominations from the database.
 * 
 */
bool8
SlotsSQL::getPreferedMachSubId(uint8 machId, uint16 preferedCreditValue, const String& login, bool8 forMoney, uint16* MachSubId)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	*MachSubId = 0;

	if ( preferedCreditValue == 0 &&
		 getLastUsedMachSubId(machId, login, forMoney, MachSubId) &&
		 *MachSubId > 0)
		return true;

    localCurrency lc;
    ok = GetLocale(&lc);

    if (!ok)
    {
        return ok;
    }

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_GetGameDenominations ");
        query->addParam((int32)GAMEID);
        query->addParam(machId);
        query->addParam(lc.int_curr_symbol);
    
        if (query->exec())
        {
            uint16  machineSubId;
            uint16  creditValue;
            bool8   isDefault;

            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, (int16*)&machineSubId);

                if ( ok )
                {
                    ok = query->getData(column++, (int16*)&creditValue);
                }
                else
                {
                    /**
                     * Invalid subMachineId.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &isDefault);
                }
                else
                {
                    /**
                     * Invalid creditValue.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    if (!preferedCreditValue && isDefault)
					{
						*MachSubId = machineSubId;
						break;
					}
					else if (preferedCreditValue >= creditValue)
					{
						*MachSubId = machineSubId;
					}
					else if (*MachSubId == 0)
					{
						*MachSubId = machineSubId;
					}
                }
                else
                {
                    /**
                     * Invalid isDefault.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}

/**
 * @brief get the denominations from the database.
 * 
 */
bool8
SlotsSQL::getLastUsedMachSubId(uint8 machId, const String& login, bool8 forMoney, uint16* MachSubId)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	*MachSubId = 0;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_SlotsGetLastMachSubId ");
        query->addParam(machId);
        query->addParam(login);
		query->addParam(forMoney);
    
        if (query->exec())
        {
            if (query->getRow())
            {
                ok = query->getData(1, (int16*)MachSubId);
            }     
			else
			{
				/**
				 * Unable to get row.
				 */
				ASSERT(0);
			}
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}

bool8 
SlotsSQL::GetLocale( localCurrency *localCurr )
{
	return (getLocale(localCurr) == NoError);
}

#ifdef DEBUGSPIN		
bool8 SlotsSQL::getDebugSpins(int32 gutsId, DebugStops& stops, int32& numRecords,PID pid)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec QATestTools_NonProd.dbo.pub_SlotsDebugGetReelSpins ");
		query->addParam(gutsId);
        query->addParam(pid);

		if (query->exec())
		{
			int32 i=0;
			while (query->getRow())
			{
				ReelDebugStops stopVals( 5 );

				ok = (query->getData(3, &stopVals[0]) && 
					query->getData(4, &stopVals[1]) && 
					query->getData(5, &stopVals[2]) && 
					query->getData(6, &stopVals[3]) && 
					query->getData(7, &stopVals[4]));					

				if ( !ok )
				{
					/**
					* Unable to get Name.
					*/
					ok = false;
					numRecords = 0;
					ASSERT(0);
					break;
				}
				else
				{
					stops.push_back(stopVals);
					numRecords++;
				}
				++i;
			}
		}
		delete query;
	}
	delete conn;

	return ok;
}	
#endif


